package com.cn.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cn.dto.OrderInfoDto;
import com.cn.entity.Goods;
import com.cn.entity.OrderInfo;
import com.cn.mapper.GoodsMapper;
import com.cn.mapper.OrderInfoMapper;
import com.cn.service.OrderInfoService;
import com.cn.utils.StringUtil;
import com.cn.utlis.Constants;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * @author: chenyuncong
 * @Date: 2020/6/28 11:48
 */
@Service("orderInfoService")
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private GoodsMapper goodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LoadingCache<Long, Goods> getGoodsCache;

    //单节点; 多节点 nginx 负载 tomcat 模式,可以防止宕机，
    @Override
    @Transactional
    public void createOrder(OrderInfoDto orderInfoDto) {
        String key = Constants.REDIS_GOODS_SIGN + orderInfoDto.getGoodsId();
        long total = redisTemplate.opsForValue().increment(key,0);
        if (orderInfoDto.getGoodsAmount() <= 0) {
            //购买商品 不能小于等于0
            return;
        }
        if (total > 0) {
            if (total >= orderInfoDto.getGoodsAmount()) {
                //由于没有用锁，这里可能会刚刚够，然后其他线程抢了一些商品，如，total=4，goodsAmount=4，这个时候其他线程抢1，当前线程需要4个，所以total=-1了，所以需要回滚，
                total = redisTemplate.opsForValue().decrement(key, orderInfoDto.getGoodsAmount().longValue());
                if (total >= 0) { //获取到的总量 大于等于0 说明没有超出
                    Goods g = getGoodsCache.get(orderInfoDto.getGoodsId());
                    if (!g.getId().equals(orderInfoDto.getGoodsId())) {
                        return;
                    }
                    OrderInfo order = toOrderInfo(orderInfoDto, g);
                    this.save(order); //插入mysql，最慢的位置,这个位置可以改成MQ削峰，消费者异步入库
                } else {
                    //有可能返回插入商品数量时候挂了，需要定时对商品数量进行矫正，使用一个单机或者定时服务器去运行，多节点用分布式锁
                    //todo lock 需要实现加锁
                    // RedisLockUtil.lock(lockKey,2, TimeUnit.SECONDS);
                    redisTemplate.opsForValue().increment(key, orderInfoDto.getGoodsAmount().longValue());
                    //todo unlock 需要实现解锁
                    //RedisLockUtil.unlock(lockKey);
                }
            } else {
                //库存不足
                return;
            }

        }
        //返回 库存不足
    }

    /**
     * 创建订单，使用本地缓存
     * @param orderInfoDto
     */
    public void createSeckillOrder(OrderInfoDto orderInfoDto){

    }

    private OrderInfo toOrderInfo(OrderInfoDto dto, Goods g) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCreateTime(System.currentTimeMillis()); //创建时间
        orderInfo.setPayTime(0L); //支付时间
        orderInfo.setDisabledTime(System.currentTimeMillis() + (10 * 60 * 1000)); // 订单失效时间 10分钟有效订单
        orderInfo.setGoodsAmount(dto.getGoodsAmount()); //商品数量
        orderInfo.setGoodsName(g.getGoodsName());       //商品名字
        orderInfo.setGoodsPrice(g.getGoodsPrice());     //商品单价
        orderInfo.setOrderNum(toOrderNum());//订单号
        orderInfo.setOrderStatus(0);                    //订单状态 0提交订单未支付，1已经支付，2已经发货，3已经收货，4已退款，5已完成
        orderInfo.setGoodsId(dto.getGoodsId());         //商品id
        orderInfo.setUserId(1L);                        //用户id
        return orderInfo;
    }

    private Long toOrderNum(){
        StringBuffer sb = new StringBuffer();
        sb.append(System.currentTimeMillis());
        sb.append(StringUtil.getRandom5());
       return Long.parseLong(sb.toString());
    }
}
